package de.rasp_disp_switch;

/* 
 * Copyright (C) 2014 http://longri.de/
 *
 * Licensed under the : GNU General Public License (GPL);
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.gnu.org/licenses/gpl.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.prefs.Preferences;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerDigital;

public class Main {

    // Retrieve the user preference node for the package de.rasp_disp_switch.Main
    private static final Preferences PREFS = Preferences.userNodeForPackage(de.rasp_disp_switch.Main.class);
    private static final String PWM_PREF_NAME = "PWM";
    private static final int MAX_PWM_VALUE = 1023;
    private static final int MIN_PWM_VALUE = 50;
    private static final int PWM_STEP = 70;

    private static int pwmValue = 1000;

    private static int lastPwmValue = -1;
    private static boolean pwmSeted = false;

    private static boolean on = true;

    /**
    * Launch the application. 
    */
    public static void main(final String[] args) {
	System.out.println("<--Pi4J--> GPIO Listen ... started.");

	final GpioController gpio = GpioFactory.getInstance();

	final GpioPinDigitalInput SW1 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_00, PinPullResistance.PULL_UP);
	final GpioPinDigitalInput SW2 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_02, PinPullResistance.PULL_UP);
	final GpioPinDigitalInput SW3 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_03, PinPullResistance.PULL_UP);
	initialPWM();

	//switch on first with last saved value
	System.out.println("Gpio => set PWM for 18 to " + pwmValue);
	on = true;
	String command = "gpio -g pwm 18 " + pwmValue;
	String output = executeCommand(command);
	System.out.println(output);

	final GpioPinListenerDigital handler = new GpioPinListenerDigital() {

	    @Override
	    public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
		// display pin state on console
		System.out.println(" --> GPIO PIN Zustand hat sich veraendert: " + event.getPin() + " = " + event.getState());

		if (event.getState() == PinState.HIGH) {

		    if (event.getPin() == SW3) {
			switchOnOff();
		    } else if (event.getPin() == SW2) {
			pwmValue += PWM_STEP;
			if (pwmValue > MAX_PWM_VALUE)
			    pwmValue = MAX_PWM_VALUE;
			setPwm(pwmValue);
		    } else if (event.getPin() == SW1) {
			pwmValue -= PWM_STEP;
			if (pwmValue < MIN_PWM_VALUE)
			    pwmValue = MIN_PWM_VALUE;
			setPwm(pwmValue);
		    }
		}
	    }
	};

	SW1.addListener(handler);
	SW2.addListener(handler);
	SW3.addListener(handler);

	do {
	    try {
		Thread.sleep(10000);
	    } catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	    }
	} while (true);

    }

    private static void initialPWM() {
	if (!pwmSeted) {
	    pwmValue = loadPwmFromPrefs();
	    System.out.println("Gpio => set PWM Mode for 18");
	    pwmSeted = true;
	    String command = "gpio -g mode 18 pwm";
	    String output = executeCommand(command);

	    System.out.println(output);
	}
    }

    private static void switchOnOff() {

	if (on) {
	    setPwm(0, false);
	} else {
	    setPwm(pwmValue);
	}
    }

    private static void setPwm(int value) {
	setPwm(value, true);
    }

    private static void setPwm(int value, boolean save) {

	if (lastPwmValue == value)
	    return;

	lastPwmValue = value;

	System.out.println("Gpio => set PWM for 18 to " + value);
	on = !on;
	String command = "gpio -g pwm 18 " + value;
	String output = executeCommand(command);
	System.out.println(output);
	if (save)
	    savePwmToPrefs(value);
    }

    /**
     * Call bash command
     * @param command
     * @return
     */
    private static String executeCommand(String command) {

	StringBuffer output = new StringBuffer();

	Process p;
	try {
	    p = Runtime.getRuntime().exec(command);
	    p.waitFor();
	    BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

	    String line = "";
	    while ((line = reader.readLine()) != null) {
		output.append(line + "\n");
	    }

	} catch (Exception e) {
	    e.printStackTrace();
	}
	return output.toString();
    }

    private static void savePwmToPrefs(int value) {
	PREFS.putInt(PWM_PREF_NAME, value);
    }

    private static int loadPwmFromPrefs() {
	int value = PREFS.getInt(PWM_PREF_NAME, MAX_PWM_VALUE);
	return value;
    }
}
